package cn.cyh.queue_service.service.impl;

import cn.cyh.queue_service.common.ResultCode;
import cn.cyh.queue_service.exception.BusinessException;
import cn.cyh.queue_service.mapper.QueueMapper;
import cn.cyh.queue_service.mapper.ServiceTypeMapper;
import cn.cyh.queue_service.mapper.UserMapper;
import cn.cyh.queue_service.mapper.WindowMapper;
import cn.cyh.queue_service.model.dto.PageRequest;
import cn.cyh.queue_service.model.dto.PageResult;
import cn.cyh.queue_service.model.dto.WindowRequest;
import cn.cyh.queue_service.model.entity.ServiceType;
import cn.cyh.queue_service.model.entity.User;
import cn.cyh.queue_service.model.entity.Window;
import cn.cyh.queue_service.model.vo.WindowVO;
import cn.cyh.queue_service.service.WindowService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 窗口服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WindowServiceImpl extends ServiceImpl<WindowMapper, Window> implements WindowService {
    
    private final WindowMapper windowMapper;
    private final UserMapper userMapper;
    private final ServiceTypeMapper serviceTypeMapper;
    private final QueueMapper queueMapper;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createWindow(WindowRequest request) {
        // 验证窗口号是否已存在
        LambdaQueryWrapper<Window> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Window::getWindowNumber, request.getWindowNumber());
        Window existingWindow = getOne(queryWrapper);
        if (existingWindow != null) {
            throw new BusinessException(ResultCode.WINDOW_NUMBER_EXISTS);
        }
        
        // 创建窗口
        Window window = Window.builder()
                .name(request.getName())
                .windowNumber(request.getWindowNumber())
                .status(StrUtil.isBlank(request.getStatus()) ? "CLOSED" : request.getStatus())
                .staffId(request.getStaffId())
                .serviceTypeId(request.getServiceTypeId())
                .currentNumber(null)
                .waitingCount(0)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        
        // 保存窗口
        save(window);
        
        return window.getId();
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWindow(Long id, WindowRequest request) {
        // 检查窗口是否存在
        Window existingWindow = getById(id);
        if (existingWindow == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        // 更新窗口
        Window window = Window.builder()
                .id(id)
                .name(request.getName())
                .description(request.getDescription())
                .status(request.getStatus())
                .updateTime(LocalDateTime.now())
                .build();
        
        return updateById(window);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteWindow(Long id) {
        // 检查窗口是否存在
        Window existingWindow = getById(id);
        if (existingWindow == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        // 检查窗口是否有未完成的业务
        if (existingWindow.getCurrentNumber() != null) {
            throw new BusinessException(ResultCode.WINDOW_IN_USE);
        }
        
        // 检查窗口状态是否为关闭
        if (!"CLOSED".equals(existingWindow.getStatus())) {
            throw new BusinessException(ResultCode.WINDOW_NOT_CLOSED);
        }
        
        // 执行删除
        return removeById(id);
    }
    
    @Override
    public WindowVO getWindowById(Long id) {
        Window window = getById(id);
        if (window == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        return convertToVO(window);
    }
    
    @Override
    public PageResult<WindowVO> getWindowList(PageRequest pageRequest) {
        IPage<Window> page = new Page<>(pageRequest.getPageNum(), pageRequest.getPageSize());
        
        // 构建查询条件
        LambdaQueryWrapper<Window> queryWrapper = new LambdaQueryWrapper<>();
        
        // 设置排序
        if (StrUtil.isNotBlank(pageRequest.getOrderBy())) {
            queryWrapper.orderBy(true, 
                    pageRequest.getIsAsc(), 
                    "create_time".equals(pageRequest.getOrderBy()) ? Window::getCreateTime : 
                    "update_time".equals(pageRequest.getOrderBy()) ? Window::getUpdateTime : 
                    "window_number".equals(pageRequest.getOrderBy()) ? Window::getWindowNumber :
                    Window::getId);
        } else {
            queryWrapper.orderByAsc(Window::getWindowNumber);
        }
        
        // 执行分页查询
        page = page(page, queryWrapper);
        
        // 转换为VO
        List<WindowVO> voList = page.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        // 构建分页结果
        return PageResult.<WindowVO>builder()
                .pageNum(pageRequest.getPageNum())
                .pageSize(pageRequest.getPageSize())
                .total(page.getTotal())
                .pages((int) page.getPages())
                .list(voList)
                .hasPrev(pageRequest.getPageNum() > 1)
                .hasNext(pageRequest.getPageNum() < page.getPages())
                .build();
    }
    
    @Override
    public List<WindowVO> getOpenWindows() {
        LambdaQueryWrapper<Window> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Window::getStatus, "OPEN")
                .orderByAsc(Window::getWindowNumber);
        
        List<Window> windowList = list(queryWrapper);
        
        return windowList.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(Long id, String status) {
        // 验证窗口是否存在
        Window window = getById(id);
        if (window == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        // 验证状态值
        if (!"OPEN".equals(status) && !"PAUSE".equals(status) && !"CLOSED".equals(status)) {
            throw new BusinessException(ResultCode.PARAM_ERROR);
        }
        
        // 如果要关闭或暂停窗口，检查是否有正在办理的业务
        if (("CLOSED".equals(status) || "PAUSE".equals(status)) && window.getCurrentNumber() != null) {
            throw new BusinessException(ResultCode.WINDOW_HAS_CURRENT_NUMBER);
        }
        
        // 更新状态
        return windowMapper.updateStatus(id, status) > 0;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateServiceType(Long id, Long serviceTypeId) {
        // 验证窗口是否存在
        Window window = getById(id);
        if (window == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        // 验证业务类型是否存在
        if (serviceTypeId != null) {
            ServiceType serviceType = serviceTypeMapper.selectById(serviceTypeId);
            if (serviceType == null) {
                throw new BusinessException(ResultCode.BUSINESS_TYPE_NOT_FOUND);
            }
            
            // 验证业务类型是否启用
            if (serviceType.getStatus() == 0) {
                throw new BusinessException(ResultCode.BUSINESS_TYPE_DISABLED);
            }
        }
        
        // 检查窗口当前是否有正在办理的业务
        if (window.getCurrentNumber() != null) {
            throw new BusinessException(ResultCode.WINDOW_HAS_CURRENT_NUMBER);
        }
        
        // 更新业务类型
        LambdaUpdateWrapper<Window> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Window::getId, id)
                .set(Window::getServiceTypeId, serviceTypeId)
                .set(Window::getUpdateTime, LocalDateTime.now());
        
        return update(updateWrapper);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCurrentNumber(Long id, String ticketNumber) {
        // 验证窗口是否存在
        Window window = getById(id);
        if (window == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        // 验证窗口状态是否为开放
        if (!"OPEN".equals(window.getStatus())) {
            throw new BusinessException(ResultCode.WINDOW_NOT_OPEN);
        }
        
        // 更新当前处理的票号
        return windowMapper.updateCurrentNumber(id, ticketNumber) > 0;
    }
    
    @Override
    public List<Window> getAvailableWindowsByServiceType(Long serviceTypeId) {
        return windowMapper.selectOpenWindowsByServiceType(serviceTypeId);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWaitingCount(Long id, Integer waitingCount) {
        // 验证窗口是否存在
        Window window = getById(id);
        if (window == null) {
            throw new BusinessException(ResultCode.WINDOW_NOT_FOUND);
        }
        
        // 更新等待人数
        return windowMapper.updateWaitingCount(id, waitingCount) > 0;
    }
    
    /**
     * 将窗口实体转换为视图对象
     */
    private WindowVO convertToVO(Window window) {
        if (window == null) {
            return null;
        }
        
        WindowVO vo = new WindowVO();
        BeanUtil.copyProperties(window, vo);
        
        // 获取业务类型名称
        if (window.getServiceTypeId() != null) {
            ServiceType serviceType = serviceTypeMapper.selectById(window.getServiceTypeId());
            if (serviceType != null) {
                vo.setServiceTypeName(serviceType.getName());
            }
        }
        
        // 获取员工姓名
        if (window.getStaffId() != null) {
            User staff = userMapper.selectById(window.getStaffId());
            if (staff != null) {
                vo.setStaffName(staff.getName());
            }
        }
        
        return vo;
    }
} 